﻿using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using _5E.Utils.DbHelper.EasySQL;
using _5E.Utils.DbHelper.EasySQL.Creator;
using _5E.Utils.DbHelper.ParameterParser;
using _5E.Utils.StringHelper.Extension;
using _5E.Utils.TypeHelper.Extension;

namespace _5E.Utils.DbHelper
{
    /// <summary>
    /// 程序说明：简易DB
    /// 创建作者：ahl5esoft
    /// 创建时间：2012-04-17
    /// </summary>
    /// <paratypeparam name="T">实体类</paratypeparam>
    public class EasyDb<T> where T : new()
    {
        #region 变量

        private const string TRUNCATE_FORMAT = "TRUNCATE TABLE {0}";

        private static EasySQLCache s_EasySQLCache = new EasySQLCache();

        private EasySQL.EasySQL m_EasySQL = null;

        private BaseCreator m_Creator = null;

        private string[] m_Columns = null;

        private string m_Where = null;

        #endregion

        #region 实例属性

        private IDb<DbConnection, DbCommand, DbParameter, DbDataAdapter> m_Db = null;
        protected IDb<DbConnection, DbCommand, DbParameter, DbDataAdapter> Db { get { return this.m_Db; } }

        #endregion

        #region 构造函数

        public EasyDb()
        {
            this.m_Db = DbFactory.BuildDb();
            this.InitEasySQL();
        }

        #endregion

        #region Query

        public T GetData(T entity)
        {
            this.SetWhere(this.m_EasySQL.PKWhere);
            var list = this.GetByEasySQL(entity);
            return list.FirstOrDefault();
        }

        public T GetData(Hashtable parameters)
        {
            this.SetWhere(this.m_EasySQL.PKWhere);
            var list = this.GetByEasySQL(parameters);
            return list.FirstOrDefault();
        }

        public List<T> GetByEasySQL(T entity)
        {
            var entityParser = DbFactory.BuildEntityParser(entity);
            var list = this.GetByQueryAndParser(entityParser);
            return list;
        }

        public List<T> GetByEasySQL(Hashtable parameters)
        {
            var hashtableParser = DbFactory.BuildHashtableParser(parameters);
            var list = this.GetByQueryAndParser(hashtableParser);
            return list;
        }

        public List<T> GetBySQL(string sql)
        {
            return this.GetBySQL(sql, null);
        }

        public List<T> GetBySQL(string sql, Hashtable parameters)
        {
            IParameterParser<DbParameter> parser = null;
            if (parameters != null && 0 < parameters.Count)
            {
                parser = DbFactory.BuildHashtableParser(parameters);
            }
            var list = QueryByParser(parser, this.m_Db, sql);
            return list;
        }

        public List<T> GetAll()
        {
            var list = this.GetByQueryAndParser(null);
            return list;
        }

        private List<T> GetByQueryAndParser(IParameterParser<DbParameter> parameterParser)
        {
            this.m_Creator = this.m_EasySQL.QueryCreator;
            var sql = this.CreateSQL();
            var list = QueryByParser(parameterParser, this.m_Db, sql);
            return list;
        }

        #endregion

        #region Insert

        public bool SaveByEasySQL(T entity)
        {
            var parser = DbFactory.BuildEntityParser(entity);
            var success = this.SaveByParser(parser);
            return success;
        }

        public bool SaveByEasySQL(Hashtable parameters)
        {
            var parser = DbFactory.BuildHashtableParser(parameters);
            var success = this.SaveByParser(parser);
            return success;
        }

        private bool SaveByParser(IParameterParser<DbParameter> parser)
        {
            var allProperty = this.m_EasySQL.AllColumns.Select(c => c.Key).ToArray();
            this.SetColumns(allProperty);
            this.m_Creator = this.m_EasySQL.InsertCreator;
            var sql = this.CreateSQL();
            var dbParameters = parser.Parse(ref sql);
            var rowCount = this.m_Db.ExecuteNonQuery(sql, dbParameters);
            return 0 < rowCount;
        }

        #endregion

        #region Update

        public bool UpdateAllByEasySQL(T entity)
        {
            var updateColumns = this.m_EasySQL.FKPropertyNames.Concat(this.m_EasySQL.OtherPropertyNames).ToArray();
            this.SetColumns(updateColumns).SetWhere(this.m_EasySQL.PKWhere);
            var success = this.UpdateByEasySQL(entity);
            return success;
        }

        public bool UpdateByEasySQL(T entity)
        {
            this.m_Creator = this.m_EasySQL.UpdateCreator;
            var sql = this.CreateSQL();
            var parser = DbFactory.BuildEntityParser(entity);
            var dbParameters = parser.Parse(ref sql);
            var rowCount = this.m_Db.ExecuteNonQuery(sql, dbParameters);
            return 0 < rowCount;
        }

        #endregion

        #region 实例方法

        private void InitEasySQL()
        {
            var type = typeof(T);
            EasySQLAttribute easySQLAttribute;
            var hasAttribute = type.TryGetAttribute(out easySQLAttribute);
            if (hasAttribute)
            {
                this.m_EasySQL = s_EasySQLCache.GetEasySQL(typeof(T));
            }
        }

        public EasyDb<T> SetColumns(params string[] columns)
        {
            this.m_Columns = columns;
            return this;
        }

        public EasyDb<T> SetWhere(string where)
        {
            this.m_Where = where;
            return this;
        }

        private string CreateSQL()
        {
            if (this.m_Creator is ICustomColumn)
            {
                (this.m_Creator as ICustomColumn).SetColumns(this.m_Columns);
            }
            if (this.m_Creator is ICustomWhere)
            {
                (this.m_Creator as ICustomWhere).SetWhere(this.m_Where);
            }
            var sql = this.m_Creator.Create();
            return sql;
        }

        #endregion

        #region 静态方法

        private static List<T> QueryByParser(IParameterParser<DbParameter> parameterParser,
            IDb<DbConnection, DbCommand, DbParameter, DbDataAdapter> db,
            string querySQL)
        {
            var sql = querySQL;
            var dbParameters = new DbParameter[] { };
            if (parameterParser != null)
            {
                dbParameters = parameterParser.Parse(ref sql);
            }
            var dataReader = db.GetDataReader(sql, dbParameters);
            var dataReaderHelper = new DataReaderHelper(dataReader, StringExtension.ToPascalCase);
            var list = dataReaderHelper.ToList<T>();
            return list;
        }

        #endregion
    }
}
